package git.soulbgm.common.base;

import git.soulbgm.common.pojo.Response;
import git.soulbgm.common.enums.CodeEnum;
import git.soulbgm.utils.ServletUtils;
import git.soulbgm.utils.StringUtil;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.util.Date;
import java.util.regex.Pattern;

/**
 * web层通用数据处理
 *
 * @author SoulBGM
 * @date 2022/03/11 13:38
 */
public class BaseController {

    private static final String[] PARSE_PATTERNS = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 仅支持字母、数字、下划线、空格、逗号、小数点（支持多个字段排序）
     */
    private static final String SQL_PATTERN = "[a-zA-Z0-9_ ,.]+";

    /**
     * 数字模式
     */
    private static final Pattern NUMBER_PATTERN = Pattern.compile("[0-9]");

    /**
     * 时间戳最大长度
     */
    private static final int TIMESTAMP_MAX_LENGTH = 13;

    /**
     * 检查字符，防止注入绕过
     */
    public static String escapeOrderBySql(String value) {
        if (StringUtil.isNotEmpty(value) && !isValidOrderBySql(value)) {
            throw new RuntimeException("参数不符合规范，不能进行查询");
        }
        return value;
    }

    /**
     * 验证 order by 语法是否符合规范
     */
    public static boolean isValidOrderBySql(String value) {
        return value.matches(SQL_PATTERN);
    }

    /**
     * 将前台传递过来的日期格式的字符串，自动转化为Date类型
     */
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // Date 类型转换
        binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) {
                setValue(parseDate(text));
            }
        });
    }

    /**
     * 日期型字符串转化为日期 格式
     *
     * @param str str
     * @return {@link Date}
     */
    public static Date parseDate(Object str) {
        if (str == null) {
            return null;
        }
        try {
            String date = str.toString();
            if (NUMBER_PATTERN.matcher(date).matches()) {
                if (date.length() <= TIMESTAMP_MAX_LENGTH) {
                    return new Date(Long.parseLong(date));
                }
            }
            return DateUtils.parseDate(date, PARSE_PATTERNS);
        } catch (ParseException e) {
            return null;
        }
    }

    /**
     * 获取request
     */
    public HttpServletRequest getRequest() {
        return ServletUtils.getRequest();
    }

    /**
     * 获取response
     */
    public HttpServletResponse getResponse() {
        return ServletUtils.getResponse();
    }

    /**
     * 获取session
     */
    public HttpSession getSession() {
        return getRequest().getSession();
    }

    /**
     * 返回成功
     */
    public Response success() {
        return Response.setOk(CodeEnum.SUCCESS);
    }

    /**
     * 返回成功
     *
     * @param code 代码
     * @return {@link Response}
     */
    public Response success(CodeEnum code) {
        return Response.setOk(code);
    }

    /**
     * 返回失败消息
     */
    public Response error() {
        return Response.setError(CodeEnum.ERROR);
    }

    /**
     * 返回成功消息
     */
    public Response success(String message) {
        return Response.setOk(CodeEnum.SUCCESS.getCode(), message);
    }

    /**
     * 返回成功数据
     */
    public static Response success(Object data) {
        return Response.setOk(CodeEnum.SUCCESS, data);
    }

    /**
     * 返回失败消息
     */
    public Response error(String message) {
        return Response.setError(CodeEnum.ERROR.getCode(), message);
    }

    /**
     * 返回失败消息和code
     *
     * @param code 代码
     * @return {@link Response}
     */
    public Response error(CodeEnum code) {
        return Response.setError(code);
    }

}
